/*
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
package com.packtpub.learningcypher.chapter4;

import java.util.HashMap;
import java.util.Map;
import org.neo4j.cypher.javacompat.ExecutionEngine;

/**
 * Benchmarks performing an operation a number of times
 * 
 * @author Onofrio Panzarino
 */
public abstract class LoopBenchmark {

    protected final ExecutionEngine engine;

    public LoopBenchmark(ExecutionEngine engine) {
        this.engine = engine;
    }

    protected abstract void findNode(int index);

    protected void run() {
        for (int i = 0; i < 4000; i++) {
            final int index = (i * 296) % 1000;
            findNode(index);
        }
    }

    public static LoopBenchmark createFinderNoParameters(ExecutionEngine engine) {
        return new LoopBenchmark(engine) {
            @Override
            protected void findNode(int index) {
                final String email = "user" + index + "@learningcypher.com";
                String query = "MATCH(n:User {email: '" + email + "'}) RETURN n";
                engine.execute(query)
                        .dumpToString();
            }
        };
    }

    public static LoopBenchmark createFinderWithParameters(ExecutionEngine engine) {
        return new LoopBenchmark(engine) {

            @Override
            protected void findNode(int index) {
                final String email = "user" + index + "@learningcypher.com";
                String query = "MATCH(n:User {email: {emailQuery}}) RETURN n";
                Map<String, Object> params = new HashMap<>();
                params.put("emailQuery", email);
                engine.execute(query, params)
                        .dumpToString();
            }
        };
    }
    
    public static LoopBenchmark createAvgCalculatorNonOptimized(ExecutionEngine engine) {
        return new LoopBenchmark(engine) {
            
            @Override
            protected void findNode(int index) {
                String query = "MATCH (user:User) -[:JOINED*]-  (group:Group)\n" +
"WITH user, COUNT(group) as countG\n" +
"RETURN avg(countG)";
                engine.execute(query).dumpToString();
            }
        };
    }
    
    public static LoopBenchmark createAvgCalculatorOptimized(ExecutionEngine engine) {
        return new LoopBenchmark(engine) {
            
            @Override
            protected void findNode(int index) {
                String query = "MATCH (user:User) -[:JOINED]-> (group:Group)\n" +
"WITH user, COUNT(group) as countG\n" +
"RETURN avg(countG)";
                engine.execute(query).dumpToString();
            }
        };
    }
}
